﻿namespace System.ServiceModel.DomainServices.Client
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Globalization;
    using System.Linq;
    using System.Reflection;
    using System.ServiceModel.DomainServices;

    internal static class ValidationUtilities
    {
        internal static IEnumerable<ValidationResult> ApplyMemberPath(IEnumerable<ValidationResult> validationResults, string memberPath)
        {
            if (string.IsNullOrEmpty(memberPath))
            {
                return validationResults;
            }
            return (from p in validationResults select ApplyMemberPath(p, memberPath));
        }

        internal static ValidationResult ApplyMemberPath(ValidationResult validationResult, string memberPath)
        {
            if (string.IsNullOrEmpty(memberPath))
            {
                return validationResult;
            }
            List<string> memberNames = new List<string>();
            foreach (string str in validationResult.MemberNames)
            {
                string item = memberPath + "." + str;
                memberNames.Add(item);
            }
            if (memberNames.Count == 0)
            {
                memberNames.Add(memberPath + ".");
            }
            return new ValidationResult(validationResult.ErrorMessage, memberNames);
        }

        internal static void ApplyValidationErrors(object instance, IEnumerable<ValidationResult> validationResults)
        {
            Entity entity = instance as Entity;
            if (entity != null)
            {
                entity.ValidationResultCollection.ReplaceErrors(validationResults);
            }
            else
            {
                ((ComplexObject) instance).ValidationResultCollection.ReplaceErrors(validationResults);
            }
            using (IEnumerator<MetaMember> enumerator = (from p in MetaType.GetMetaType(instance.GetType()).DataMembers
                where p.IsComplex && !p.IsCollection
                select p).GetEnumerator())
            {
                Func<ValidationResult, bool> func = null;
                MetaMember complexMember;
                while (enumerator.MoveNext())
                {
                    complexMember = enumerator.Current;
                    if (func == null)
                    {
                        func = p => Enumerable.Any<string>(p.MemberNames, (Func<string, bool>) (q => (!string.IsNullOrEmpty(q) && q.StartsWith(complexMember.Member.Name + ".", StringComparison.Ordinal))));
                    }
                    IEnumerable<ValidationResult> enumerable = Enumerable.Where<ValidationResult>(validationResults, func);
                    ComplexObject obj2 = (ComplexObject) complexMember.GetValue(instance);
                    if (obj2 != null)
                    {
                        enumerable = RemoveMemberPrefix(enumerable, complexMember.Member.Name);
                        ApplyValidationErrors(obj2, enumerable);
                    }
                }
            }
        }

        internal static ValidationContext CreateValidationContext(object instance, ValidationContext parentContext)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }
            return new ValidationContext(instance, parentContext, (parentContext != null) ? parentContext.Items : null);
        }

        private static DisplayAttribute GetDisplayAttribute(ICustomAttributeProvider member)
        {
            return (member.GetCustomAttributes(typeof(DisplayAttribute), true).SingleOrDefault<object>() as DisplayAttribute);
        }

        internal static MethodInfo GetMethod(object instance, string methodName, object[] parameters)
        {
            Type type = instance.GetType();
            MethodInfo[] infoArray = (from m in type.GetMethods()
                where (m.Name == methodName) && IsBindable(m, parameters)
                select m).ToArray<MethodInfo>();
            if (infoArray.Length == 0)
            {
                int num = (parameters == null) ? 0 : parameters.Length;
                if (num == 0)
                {
                    throw new MissingMethodException(string.Format(CultureInfo.CurrentCulture, Resource.ValidationUtilities_MethodNotFound_ZeroParams, new object[] { type, methodName }));
                }
                string[] strArray = Enumerable.Select<object, string>(parameters, delegate (object p) {
                    if (p != null)
                    {
                        return string.Format(CultureInfo.InvariantCulture, "'{0}'", new object[] { p.GetType().ToString() });
                    }
                    return "null";
                }).ToArray<string>();
                throw new MissingMethodException(string.Format(CultureInfo.CurrentCulture, Resource.ValidationUtilities_MethodNotFound, new object[] { type, methodName, num, string.Join(", ", strArray) }));
            }
            if (infoArray.Length > 1)
            {
                throw new AmbiguousMatchException(string.Format(CultureInfo.CurrentCulture, Resource.ValidationUtilities_AmbiguousMatch, new object[] { methodName }));
            }
            return infoArray[0];
        }

        internal static bool IsBindable(Type[] parameterTypes, object[] parameters)
        {
            int num = (parameters == null) ? 0 : parameters.Length;
            if (parameterTypes.Length != num)
            {
                return false;
            }
            for (int i = 0; i < num; i++)
            {
                if (parameters[i] == null)
                {
                    if (!TypeUtility.IsNullableType(parameterTypes[i]) && parameterTypes[i].IsValueType)
                    {
                        return false;
                    }
                }
                else if (!parameterTypes[i].IsAssignableFrom(parameters[i].GetType()))
                {
                    return false;
                }
            }
            return true;
        }

        internal static bool IsBindable(MethodInfo method, object[] parameters)
        {
            return IsBindable((from p in method.GetParameters() select p.ParameterType).ToArray<Type>(), parameters);
        }

        internal static bool MethodRequiresValidation(MethodInfo method)
        {
            if (method.GetCustomAttributes(true).OfType<ValidationAttribute>().Any<ValidationAttribute>())
            {
                return true;
            }
            foreach (ParameterInfo info in method.GetParameters())
            {
                if (info.GetCustomAttributes(true).OfType<ValidationAttribute>().Any<ValidationAttribute>())
                {
                    return true;
                }
            }
            return false;
        }

        private static string NormalizeMemberPath(string memberPath, Type memberType)
        {
            if (!string.IsNullOrEmpty(memberPath) && typeof(IEnumerable).IsAssignableFrom(memberType))
            {
                return (memberPath + "()");
            }
            return memberPath;
        }

        internal static IEnumerable<ValidationResult> RemoveMemberPrefix(IEnumerable<ValidationResult> validationResults, string memberName)
        {
            if (string.IsNullOrEmpty(memberName))
            {
                return validationResults;
            }
            List<ValidationResult> list = new List<ValidationResult>();
            foreach (ValidationResult result in validationResults)
            {
                List<string> memberNames = new List<string>();
                foreach (string str in result.MemberNames)
                {
                    if (!string.IsNullOrEmpty(str))
                    {
                        string item = str;
                        string str3 = memberName + ".";
                        if (item.StartsWith(str3, StringComparison.Ordinal))
                        {
                            item = item.Substring(str3.Length);
                        }
                        if (item.Length > 0)
                        {
                            memberNames.Add(item);
                        }
                    }
                }
                list.Add(new ValidationResult(result.ErrorMessage, memberNames));
            }
            return list;
        }

        internal static bool TryValidateCustomUpdateMethodCall(string methodName, ValidationContext validationContext, object[] parameters, List<ValidationResult> validationResults)
        {
            return ValidateMethodCall(methodName, validationContext, parameters, validationResults, true);
        }

        public static bool TryValidateObject(object instance, ValidationContext validationContext, List<ValidationResult> validationResults)
        {
            return ValidateObjectRecursive(instance, string.Empty, validationContext, validationResults);
        }

        private static bool ValidateComplexCollection(IEnumerable elements, string memberPath, ValidationContext validationContext, List<ValidationResult> validationResults)
        {
            bool flag = false;
            foreach (object obj2 in elements)
            {
                if (obj2 != null)
                {
                    flag |= !ValidateObjectRecursive(obj2, memberPath + "()", validationContext, validationResults);
                }
            }
            return !flag;
        }

        internal static void ValidateCustomUpdateMethodCall(string methodName, ValidationContext validationContext, object[] parameters)
        {
            ValidateMethodCall(methodName, validationContext, parameters, null, true);
        }

        internal static void ValidateMethodCall(string methodName, ValidationContext validationContext, object[] parameters)
        {
            ValidateMethodCall(methodName, validationContext, parameters, null, false);
        }

        internal static bool ValidateMethodCall(string methodName, ValidationContext validationContext, object[] parameters, List<ValidationResult> validationResults, bool performTypeValidation)
        {
            if (string.IsNullOrEmpty(methodName))
            {
                throw new ArgumentNullException("methodName");
            }
            if (validationContext == null)
            {
                throw new ArgumentNullException("validationContext");
            }
            if (validationContext.ObjectInstance == null)
            {
                throw new ArgumentException(Resource.ValidationUtilities_ContextInstance_CannotBeNull, "validationContext");
            }
            MethodInfo member = GetMethod(validationContext.ObjectInstance, methodName, parameters);
            ValidationContext context = CreateValidationContext(validationContext.ObjectInstance, validationContext);
            context.MemberName = member.Name;
            DisplayAttribute displayAttribute = GetDisplayAttribute(member);
            if (displayAttribute != null)
            {
                context.DisplayName = displayAttribute.GetName();
            }
            string str = string.Empty;
            if (performTypeValidation)
            {
                str = member.Name + ".";
            }
            IEnumerable<ValidationAttribute> validationAttributes = member.GetCustomAttributes(typeof(ValidationAttribute), true).Cast<ValidationAttribute>();
            bool flag = ValidateValue(validationContext.ObjectInstance, context, validationResults, validationAttributes, string.Empty);
            ParameterInfo[] infoArray = member.GetParameters();
            for (int i = 0; i < infoArray.Length; i++)
            {
                ParameterInfo info2 = infoArray[i];
                object obj2 = (parameters.Length > i) ? parameters[i] : null;
                ValidationContext context2 = CreateValidationContext(validationContext.ObjectInstance, validationContext);
                context2.MemberName = info2.Name;
                string name = info2.Name;
                displayAttribute = GetDisplayAttribute(info2);
                if (displayAttribute != null)
                {
                    name = displayAttribute.GetName();
                }
                context2.DisplayName = name;
                string memberPath = str;
                if (performTypeValidation)
                {
                    memberPath = memberPath + info2.Name;
                }
                IEnumerable<ValidationAttribute> enumerable2 = info2.GetCustomAttributes(typeof(ValidationAttribute), false).Cast<ValidationAttribute>();
                bool flag2 = ValidateValue(obj2, context2, validationResults, enumerable2, NormalizeMemberPath(memberPath, info2.ParameterType));
                if ((flag2 && performTypeValidation) && (obj2 != null))
                {
                    Type parameterType = info2.ParameterType;
                    if (validationResults == null)
                    {
                        if (TypeUtility.IsComplexType(parameterType))
                        {
                            ValidationContext context3 = CreateValidationContext(obj2, context2);
                            context3.DisplayName = name;
                            Validator.ValidateObject(obj2, context3, true);
                        }
                    }
                    else if (TypeUtility.IsComplexType(parameterType))
                    {
                        flag2 = ValidateObjectRecursive(obj2, memberPath, validationContext, validationResults);
                    }
                    else if (TypeUtility.IsComplexTypeCollection(parameterType))
                    {
                        flag2 = ValidateComplexCollection(obj2 as IEnumerable, memberPath, validationContext, validationResults);
                    }
                }
                flag &= flag2;
            }
            return flag;
        }

        private static bool ValidateObjectRecursive(object instance, string memberPath, ValidationContext validationContext, List<ValidationResult> validationResults)
        {
            MetaType metaType = MetaType.GetMetaType(instance.GetType());
            if (!metaType.RequiresValidation)
            {
                return true;
            }
            bool flag = false;
            foreach (MetaMember member in Enumerable.Where<MetaMember>(metaType.Members, delegate (MetaMember m) {
                if (!m.RequiresValidation)
                {
                    return m.IsComplex;
                }
                return true;
            }))
            {
                ValidationContext context = CreateValidationContext(instance, validationContext);
                context.MemberName = member.Member.Name;
                string str = memberPath;
                if (member.IsComplex)
                {
                    if (str.Length > 0)
                    {
                        str = str + ".";
                    }
                    str = str + member.Member.Name;
                }
                object obj2 = member.GetValue(instance);
                if (member.RequiresValidation)
                {
                    flag |= !ValidateProperty(obj2, context, validationResults, str);
                }
                if ((obj2 != null) && member.IsComplex)
                {
                    if (!member.IsCollection)
                    {
                        flag |= !ValidateObjectRecursive(obj2, str, validationContext, validationResults);
                    }
                    else
                    {
                        flag |= !ValidateComplexCollection((IEnumerable) obj2, str, validationContext, validationResults);
                    }
                }
            }
            if (flag)
            {
                return false;
            }
            ValidationContext context2 = CreateValidationContext(instance, validationContext);
            if (metaType.ValidationAttributes.Any<ValidationAttribute>())
            {
                flag |= !ValidateValue(instance, context2, validationResults, metaType.ValidationAttributes, memberPath);
            }
            return !flag;
        }

        private static bool ValidateProperty(object value, ValidationContext validationContext, List<ValidationResult> validationResults, string memberPath)
        {
            if (validationResults == null)
            {
                Validator.ValidateProperty(value, validationContext);
            }
            else
            {
                List<ValidationResult> list = new List<ValidationResult>();
                if (!Validator.TryValidateProperty(value, validationContext, list))
                {
                    if (memberPath.Length > 0)
                    {
                        list = ApplyMemberPath(list, memberPath).ToList<ValidationResult>();
                    }
                    validationResults.AddRange(list);
                    return false;
                }
            }
            return true;
        }

        private static bool ValidateValue(object value, ValidationContext validationContext, List<ValidationResult> validationResults, IEnumerable<ValidationAttribute> validationAttributes, string memberPath)
        {
            if (validationResults == null)
            {
                Validator.ValidateValue(value, validationContext, validationAttributes);
            }
            else
            {
                List<ValidationResult> list = new List<ValidationResult>();
                if (!Validator.TryValidateValue(value, validationContext, list, validationAttributes))
                {
                    if (!string.IsNullOrEmpty(memberPath))
                    {
                        list = ApplyMemberPath(list, memberPath).ToList<ValidationResult>();
                    }
                    validationResults.AddRange(list);
                    return false;
                }
            }
            return true;
        }
    }
}

